package com.zf.validation.exception;

import com.zf.common.core.result.RestResponse;
import com.zf.common.core.result.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.HashMap;

/**
 * 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 参数绑定到 java bean 出错时抛出 BindException 异常
     */
    @ExceptionHandler(BindException.class)
    public RestResponse<Void> bindExceptionHandler(BindException e){
        log.error(e.getMessage(), e);
        BindingResult bindingRestResponse = e.getBindingResult();
        FieldError fieldError = bindingRestResponse.getFieldError();
        return RestResponse.failed(ResultCodeEnum.PARAM_VALID_ERROR.getCode(), fieldError.getDefaultMessage());
    }

    /**
     * 处理java bean校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestResponse<Void> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
        log.error(e.getMessage(), e);
        //获取表单校验错误的结果
        BindingResult bindingRestResponse = e.getBindingResult();
        //获取被校验类的Class
        Class<?> target = bindingRestResponse.getTarget().getClass();
        //获取第一个校验错误字段的信息
        FieldError fieldError = bindingRestResponse.getFieldError();
        //属性名
        String field = fieldError.getField();
        //错误提示
        String message = fieldError.getDefaultMessage();
        return RestResponse.failed(ResultCodeEnum.PARAM_VALID_ERROR.getCode(), message);
    }

    /**
     * 普通参数(非 java bean)校验出错时抛出 ConstraintViolationException 异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public RestResponse<Void> processException(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        HashMap<String, String> msg = new HashMap<>();
        e.getConstraintViolations().forEach(constraintViolation -> {
            String template = constraintViolation.getMessage();//错误信息
            String path = constraintViolation.getPropertyPath().toString();// 所在方法的方法名.校验字段名
            msg.put(path, template);
        });
        return RestResponse.failed(ResultCodeEnum.PARAM_ERROR, msg.toString());
    }

    @ExceptionHandler(ValidationException.class)
    public RestResponse<Void> processException(ValidationException e) {
        log.error(e.getMessage(), e);
        return RestResponse.failed(ResultCodeEnum.PARAM_ERROR, "参数校验失败");
    }

    
    @ExceptionHandler(Exception.class)
    public RestResponse<Void> handleException(Exception e) {
        log.error(e.getMessage(), e);
        return RestResponse.failed(e.getMessage());
    }
}
